using System;
using System.Collections;

namespace Slaks.Graphs
{
	public class Vertex : IComparable
	{
		protected long m_id;
		protected double m_frequency;

		protected SectionType2EdgeListMap m_sectionType2EdgeListMap;

		public Vertex(long id)
		{
			m_id = id;
			m_frequency = 1;
			this.Init();
		}

		public Vertex(long id, double frequency)
		{
			m_id = id;
			m_frequency = frequency;
			this.Init();
		}

		public long GetId()
		{
			return m_id;
		}


		public double Frequency
		{
			get { return m_frequency; }
			set { m_frequency = value; }
		}

		public Edge AddEdge(Vertex target, string sectionType)
		{
			Edge edge = this.IsEdgeExists(target.GetId(), sectionType);
			if (edge != null)
			{
				edge.IncreseFrequency();
				return edge;
			}

			edge = new Edge(target, sectionType);
			EdgeList edgeList;
			if (m_sectionType2EdgeListMap.Contains(sectionType)) edgeList = m_sectionType2EdgeListMap[sectionType];
			else
			{
				edgeList = new EdgeList();
				m_sectionType2EdgeListMap.Add(sectionType, edgeList);
			}
			edgeList.Add(edge);
			return edge;
		}

		public IDictionary GetSectionsIfConnected(long id)
		{
			IDictionary sections = new Hashtable();
			object obj = new object();
			ICollection keySection = m_sectionType2EdgeListMap.Keys;

			EdgeList list;
			foreach (string section in keySection)
			{
				list = m_sectionType2EdgeListMap[section];

				foreach (Edge edge in list)
				{
					if (edge.GetTarget().GetId() == id)
					{
						sections.Add(section, obj);
						break;
					}
				}
			}

			return sections;
		}

		/// <summary>
		/// Checks whether the edge exists. If yes returns the edge otherwise returns null
		/// </summary>
		public Edge IsEdgeExists(long targetId, string sectionType)
		{
			if (m_sectionType2EdgeListMap.Contains(sectionType) == false) return null;

			EdgeList edgeList = m_sectionType2EdgeListMap[sectionType];
			Edge edge = null;
			for (int i = 0; i < edgeList.Count; i++)
			{
				edge = edgeList[i];
				if (edge.GetTarget().GetId() == targetId) return edge;
			}

			return null;
		}

		public Edge IsEdgeExists(Vertex target, string sectionType)
		{
			return this.IsEdgeExists(target.GetId(), sectionType);
		}

		public double GetEdgeFrequency(long targetId, string sectionType)
		{
			if (m_sectionType2EdgeListMap.Contains(sectionType) == false) return 0;

			EdgeList edgeList = m_sectionType2EdgeListMap[sectionType];
			Edge edge = null;
			for (int i = 0; i < edgeList.Count; i++)
			{
				edge = edgeList[i];
				if (edge.GetTarget().GetId() == targetId) return edge.GetFrequency();
			}

			return 0;
		}

		public long CountEdges()
		{
			long edgeCount = 0;

			ICollection edgeLists = m_sectionType2EdgeListMap.Values;

			foreach (EdgeList list in edgeLists)
			{
				edgeCount += list.Count;
			}
			return edgeCount;
		}

		private void Init()
		{
			m_sectionType2EdgeListMap = new SectionType2EdgeListMap();
		}

		public override bool Equals(object obj)
		{
			if (obj is Vertex)
				if (this.CompareTo((Vertex) obj) == 0) return true;
			return false;
		}

		public SectionType2EdgeListMap GetSection2EdgeMap()
		{
			return m_sectionType2EdgeListMap;
		}

		#region IComparable Members

		public int CompareTo(Vertex obj)
		{
			if (this.m_id < obj.m_id) return -1;
			else if (this.m_id == obj.m_id) return 0;
			return 1;
		}
		public override int GetHashCode ()
		{
			return this.m_id.GetHashCode();
		}
		public int CompareTo(object obj)
		{
			Vertex vertex = obj as Vertex;
			if (vertex == null) throw new ArgumentException("Object passed for comparison is not Vertex");
			return this.CompareTo(vertex);
		}

		#endregion
	}
}